import React, { Component } from 'react';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { action, observable } from 'mobx';
import { observer } from 'mobx-react';
import
{
    BoxGeometry, Mesh, MeshBasicMaterial, TextureLoader, Object3D,
    Scene, SphereGeometry, WebGLRenderer, ArrowHelper, Vector3, Camera, PerspectiveCamera, Sprite, Raycaster, Vector2, SpriteMaterial, RepeatWrapping
} from 'three';
import scene_full from '../../assets/img/scene.jpeg';
import hot from '../../assets/img/hot.png';
import tri_pattern from '../../assets/img/tri_pattern.jpg';
import { FXAAShader } from "three/examples/jsm/shaders/FXAAShader.js";
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js";
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";


interface WebVRSphereProps
{
    imgUrl?: string;
}

@observer
export default class WebVRSphere extends Component<WebVRSphereProps, {}>
{
    constructor(props: WebVRSphereProps)
    {
        super(props);
    }
    @observable myScene = document.getElementById("vrScene") as HTMLDivElement;
    /*
        ThreeJS最重要的三个东西
    */
    @observable scene = new Scene(); // 场景
    @observable camera = new PerspectiveCamera(
        75, //视野角度
        this.myScene.offsetWidth / this.myScene.offsetHeight, //长宽比
        0.1, //近截面
        1000 //远截面
    );
    @observable renderer = new WebGLRenderer(); //渲染器


    @observable geometryCube = new BoxGeometry(100, 100, 100); //几何图形:建一个什么样的形状,这是一个正方体
    @observable geometrySphere = new SphereGeometry(40, 50, 50); //这是一个球体{1.半径 2.垂直节点数 3.水平节点数}
    @observable materials = new MeshBasicMaterial({ map: new TextureLoader().load(this.makeImage(), () => { this.loop(); }) });  //材质的选择决定是否受光照影响,来自定义一个材质;
    @observable control = new OrbitControls(this.camera, this.renderer.domElement);//控制相机到处看
    //三根辅助箭头
    @observable arrowHelperY = new ArrowHelper(new Vector3(0, 1, 0), new Vector3(0, 0, 0), 10, 0x00ff00);
    @observable arrowHelperX = new ArrowHelper(new Vector3(1, 0, 0), new Vector3(0, 0, 0), 10, 0xff0000);
    @observable arrowHelperZ = new ArrowHelper(new Vector3(0, 0, 1), new Vector3(0, 0, 0), 10, 0x0000ff);
    @observable cube = new Mesh(this.geometryCube, this.materials);
    @observable sphere = new Mesh(this.geometrySphere, this.materials);
    pointMaterial = new SpriteMaterial({ map: new TextureLoader().load(hot, () => { this.loop(); }) });

    hotPoints = [
        {
            position: {
                x: 35,
                y: 0,
                z: -2
            },
            detail: {
                "title": "门"
            }
        },
        {
            position: {
                x: -25,
                y: -7,
                z: -25
            },
            detail: {
                "title": "电视机"
            }
        }
    ];
    @observable poiOb: Sprite[] = []; //这个数组保存的是场景里所有的3D模型，用intersectObjects()来判断那个被点中
    @observable poiObBorder: Object3D[] = [];
    @action
    setUp = (scene: Scene, camera: Camera, renderer: WebGLRenderer, el: HTMLDivElement) =>
    {
        // this.sphere.material.wireframe = true;
        this.sphere.geometry.scale(1, 1, -1);
        scene.add(this.sphere);

        scene.add(this.arrowHelperY);
        scene.add(this.arrowHelperX);
        scene.add(this.arrowHelperZ);

        this.hotPoints.forEach(element =>
        {
            let sprite = new Sprite(this.pointMaterial);
            sprite.scale.set(10, 10, 10);
            sprite.position.set(element.position.x, element.position.y, element.position.z);
            sprite.userData = element.detail;
            this.poiOb.push(sprite);
            scene.add(sprite);
        });

        //设置渲染器的尺寸,就是canvas的宽高
        renderer.setSize(el.offsetWidth, el.offsetHeight);
        //设置canvas的背景颜色就是场景背景颜色(???但是为什么不是scene里面设置呢?)
        this.renderer.setClearColor(0xb9d3ff, 1);
        el.appendChild(renderer.domElement);

        camera.position.set(0, 0, 10);
        camera.lookAt(scene.position);

        this.loop();
    };

    @action
    loop = () =>
    {
        // this.renderer.render(this.scene, this.camera);
        this.composer.render();
    };

    raycast = (e: MouseEvent) =>
    {
        let canvas = e.target as HTMLCanvasElement;
        e.preventDefault();

        let raycaster = new Raycaster();
        let mouse = new Vector2();
        console.log(e.clientX);
        //将鼠标点击位置的屏幕坐标转成threejs中的标准坐标
        mouse.x = ((e.clientX - 256) / canvas.clientWidth) * 2 - 1;
        mouse.y = -(e.clientY / canvas.clientHeight) * 2 + 1;

        raycaster.setFromCamera(mouse, this.camera);
        let intersect = raycaster.intersectObjects(this.poiOb);//存放所有想要被获取的3D模型对象

        if (intersect.length > 0)
        {
            this.poiObBorder = [];
            this.poiObBorder.push(intersect[0].object);
            this.outlinepass.selectedObjects = this.poiObBorder;
            this.composer.render();
            console.log(intersect);
        }
        else
        {
            this.outlinepass.selectedObjects = [];
            this.composer.render();
        }

    };
    @observable composer = new EffectComposer(this.renderer);
    @observable outlinepass = new OutlinePass(new Vector2(this.myScene.offsetWidth, this.myScene.offsetHeight), this.scene, this.camera);

    setUpComposer() //初始化效果编辑器
    {
        this.composer.setSize(this.myScene.offsetWidth, this.myScene.offsetHeight);

        const renderpass = new RenderPass(this.scene, this.camera);
        this.composer.addPass(renderpass);
        this.composer.addPass(this.outlinepass);

        const textureLoader = new TextureLoader();
        textureLoader.load(tri_pattern, (texture) =>
        {
            this.outlinepass.patternTexture = texture;
            texture.wrapS = RepeatWrapping;
            texture.wrapT = RepeatWrapping;
        });

        const effectFXAA = new ShaderPass(FXAAShader);
        effectFXAA.uniforms['resolution'].value.set(
            1 / this.myScene.offsetWidth, 1 / this.myScene.offsetHeight
        );
        this.composer.addPass(effectFXAA);

        this.renderer.domElement.addEventListener('click', (e) => { this.raycast(e); });
    }


    makeImage(): string
    {
        if (this.props.imgUrl) return this.props.imgUrl;
        return scene_full;
    }

    componentDidMount()
    {
        this.setUpComposer();

        this.setUp(this.scene, this.camera, this.renderer, this.myScene);

        this.control.addEventListener('change', this.loop);
    }

    render()
    {
        return (
            <div id="vrScene" style={{ width: "800px", height: "700px" }}>
            </div>
        );
    }
}
